<?php
namespace App\Controller;

use App\Model\UserScoreLog;
use App\Model\User;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Contract\ConfigInterface;

class RankController extends AbstractController
{

    public function rankingList()
    {
        $score_conf = config('score');
        $rank_key = $score_conf['score_rank'];

        $curr = date("Y-m-d");
        $w = date('w');//获取当前周的第几天 周日是 0 周一到周六是1-6
        $beginLastWeek = strtotime("$curr -" . ($w ? $w - 1 : 6) . ' days');//获取本周开始日期，如果$w是0是周日:-6天;其它:-1天
        $start = date('Y-m-d 00:00:00', $beginLastWeek);
        $end = date('Y-m-d 23:59:59', strtotime("$start +6 days"));
        $date_between = [strtotime($start, time()), strtotime($end, time())];
        if (redis()->exists($rank_key)) {
            // 从缓存获取排行榜
            $rankList = redis()->zRevRange($rank_key, 0, 99, true);
        } else {
            // 从数据库获取，并存入有序集合
            $total_win = UserScoreLog::totalWinGroup($date_between);
            $total_lose = UserScoreLog::totalLoseGroup($date_between);
            $user_data = $this->rankScore($total_win, $total_lose);
            // 存入有序集合
            $this->storeIntoSort($user_data);
            $rankList = redis()->zRevRange($rank_key, 0, 99, true);
        }
        if (!empty($rankList)) {
            $data['rank'] = $this->rankWithInfo($rankList);
            $userInfo = $this->getUserInfo();
            $data['user_score'] = $this->userRank($userInfo['uid']);
            return $this->output(1, 'success', $data);
        } else {
            return $this->output(400, '暂无数据！');
        }
    }

    /**
     * 用户排行榜数据
     * @param $rankList
     * @return array
     */
    private function rankWithInfo($rankList)
    {
        // 查询用户信息
        $uids = [];
        foreach ($rankList as $k => $v) {
            $uids[] = $k;
        }
        $info = User::getUsers($uids);
        $return = [];
        foreach ($uids as $k => $v) {
            foreach ($info['data'] as $ks => $vs) {
                if ($vs['account'] == $v) {
                    $user_info['account'] = $vs['account'];
                    $user_info['nickname'] = $vs['nickname'];
                    $user_info['avatar'] = $vs['avatar'];
                    $user_info['score'] = $rankList[$vs['account']];
                    $return[] = $user_info;
                    break;
                }
            }
        }
        return $return;
    }

    /**
     * 用户排名积分
     * @param $win
     * @param $lose
     * @return array
     */
    private function rankScore($win, $lose)
    {
        $win_arr = [];
        $lose_arr = [];
        foreach ($win as $k => $v) {
            $win_arr[$v['account']] = $v['score'];
        }
        foreach ($lose as $kk => $vv) {
            $lose_arr[$vv['account']] = $vv['score'];
        }
        $new_arr = [];
        foreach ($win_arr as $ks => $vs) {
            if (isset($lose_arr[$ks])) {
                $new_arr[$ks] = $vs - $lose_arr[$ks];
                unset($lose_arr[$ks]);
            } else {
                $new_arr[$ks] = $vs;
            }
        }
        if (!empty($lose_arr)) {
            foreach ($lose_arr as $kk => $vv) {
                $new_arr[$kk] = $vv;
            }
        }
        return $new_arr;
    }


    /**
     * 存入有序集合
     */
    private function storeIntoSort($data)
    {
        $redis = redis();
        $score_conf = config('score');
        $score_rank_key = $score_conf['score_rank'];

        $date = new \DateTime();//时间对象
        $date->modify("this week +6 days");//该周的最后一天
        $end_time = $date->format('Y-m-d') . ' 23:59:59';
        $expire = strtotime($end_time) - time();

        $arr = array($score_rank_key);
        foreach ($data as $k => $v) {
            array_push($arr, (int)$v);
            array_push($arr, (string)$k);
        }
        call_user_func_array(array($redis, 'zadd'), $arr);
        $redis->expire($score_rank_key, $expire);
    }

    /**
     * 获取指定member的积分
     * @param $uid
     * @return bool|float
     */
    protected function userRank($uid)
    {
        $score_conf = config('score');
        $score = redis()->zScore($score_conf['score_rank'], (string)$uid);
        if (!$score) {
            $score = 0;
        }
        return $score;
    }
}